#include "spi.h"

#define LCD_HOST SPI2_HOST

_lcd_dev lcddev;
spi_device_handle_t spi;

void spi_Init(void)
{
    gpio_set_direction(GPIO_LCD_DC, GPIO_MODE_OUTPUT);
    gpio_set_direction(GPIO_LCD_RST, GPIO_MODE_OUTPUT);
    gpio_set_direction(GPIO_LCD_CS, GPIO_MODE_OUTPUT);

    //Reset the display
    gpio_set_level(GPIO_LCD_RST, 0);
    vTaskDelay(100 / portTICK_RATE_MS);
    gpio_set_level(GPIO_LCD_RST, 1);
    vTaskDelay(100 / portTICK_RATE_MS);

    esp_err_t ret;
    spi_bus_config_t buscfg={
        .miso_io_num = -1,
        .mosi_io_num = GPIO_LCD_DAT,
        .sclk_io_num = GPIO_LCD_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 128*160*2+8
    };

    spi_device_interface_config_t devcfg={
        .clock_speed_hz = 40*1000*1000,
        .mode = 0,
        .spics_io_num = GPIO_LCD_CS,              // CS pin
        .input_delay_ns = 0,
        .queue_size = 7,
        .pre_cb=NULL,
        .post_cb=NULL,
        .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_HALFDUPLEX,	/* dummy bits should be explicitly handled via DISP_SPI_VARIABLE_DUMMY as needed */
    };
    //Initialize the SPI bus
    ret=spi_bus_initialize(LCD_HOST, &buscfg, 1);
    ESP_ERROR_CHECK(ret);
    //Attach the LCD to the SPI bus
    ret=spi_bus_add_device(LCD_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);
}

void SPI_Transfer(uint8_t data)
{
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.length = 8;                     //Command is 8 bits
    t.tx_buffer = &data;               //The data is the data itself
    t.user = (void*)0;                //D/C needs to be set to 0
    ret = spi_device_polling_transmit(spi, &t);  //Transmit!
    assert(ret == ESP_OK);            //Should have had no issues.
}

void LCD_WR_REG(uint16_t regval)
{ 
	SPILCD_CS_RESET;  //LCD_CS=0
    SPILCD_RS_RESET;
    SPI_Transfer(regval);
	SPILCD_CS_SET;  //LCD_CS=1
}

void LCD_WR_DATA(uint16_t data)
{
 	SPILCD_CS_RESET;  //LCD_CS=0
	SPILCD_RS_SET;
	SPI_Transfer(data>>8);
	SPI_Transfer(data);
	SPILCD_CS_SET;  //LCD_CS=1		
}

void LCD_WR_DATA8(uint8_t da)
{
	SPILCD_CS_RESET;  //LCD_CS=0
	SPILCD_RS_SET;
	SPI_Transfer(da);
	SPILCD_CS_SET;  //LCD_CS=1
}

void LCD_WR_REG_DATA(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{
	LCD_WR_REG(LCD_Reg);
	LCD_WR_DATA(LCD_RegValue);
}

void LCD_WriteRAM_Prepare(void)
{
	LCD_WR_REG(lcddev.wramcmd);  
}

void LCD_DisplayOn(void)
{

}

void LCD_DisplayOff(void)
{

}

void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
    LCD_WR_REG(lcddev.setxcmd);
	LCD_WR_DATA8(Xpos>>8);
	LCD_WR_DATA8(Xpos&0XFF);
	LCD_WR_REG(lcddev.setycmd);
	LCD_WR_DATA8(Ypos>>8);
	LCD_WR_DATA8(Ypos&0XFF);
} 	  

void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color)
{
	LCD_SetCursor(x,y);		//���ù��λ�� 
	LCD_WriteRAM_Prepare();	//��ʼд��GRAM
	LCD_WR_DATA(color);
} 

void LCD_Init(void)
{
	SPILCD_RST_RESET ;	//LCD_RST=0	 //SPI�ӿڸ�λ
	vTaskDelay(pdMS_TO_TICKS(20));
    SPILCD_RST_SET ;	//LCD_RST=1
    vTaskDelay(pdMS_TO_TICKS(20));

	lcddev.width=128;
	lcddev.height=160;
	lcddev.wramcmd=0X2C;
	lcddev.setxcmd=0X2A;
	lcddev.setycmd=0X2B;

    LCD_WR_REG(0x05);

	LCD_WR_REG(0x11); //Sleep out
	vTaskDelay(pdMS_TO_TICKS(120));
	//------------------------------------ST7735S Frame Rate-----------------------------------------//
	LCD_WR_REG(0xB1);
	LCD_WR_DATA8(0x05);
	LCD_WR_DATA8(0x3C);
	LCD_WR_DATA8(0x3C);
	LCD_WR_REG(0xB2);
	LCD_WR_DATA8(0x05);
	LCD_WR_DATA8(0x3C);
	LCD_WR_DATA8(0x3C);
	LCD_WR_REG(0xB3);
	LCD_WR_DATA8(0x05);
	LCD_WR_DATA8(0x3C);
	LCD_WR_DATA8(0x3C);
	LCD_WR_DATA8(0x05);
	LCD_WR_DATA8(0x3C);
	LCD_WR_DATA8(0x3C);
	//------------------------------------End ST7735S Frame Rate-----------------------------------------//
	LCD_WR_REG(0xB4); //Dot inversion
	LCD_WR_DATA8(0x03);
	LCD_WR_REG(0xC0);
	LCD_WR_DATA8(0x28);
	LCD_WR_DATA8(0x08);
	LCD_WR_DATA8(0x04);
	LCD_WR_REG(0xC1);
	LCD_WR_DATA8(0XC0);
	LCD_WR_REG(0xC2);
	LCD_WR_DATA8(0x0D);
	LCD_WR_DATA8(0x00);
	LCD_WR_REG(0xC3);
	LCD_WR_DATA8(0x8D);
	LCD_WR_DATA8(0x2A);
	LCD_WR_REG(0xC4);
	LCD_WR_DATA8(0x8D);
	LCD_WR_DATA8(0xEE);
	//---------------------------------End ST7735S Power Sequence-------------------------------------//
	LCD_WR_REG(0xC5); //VCOM
	LCD_WR_DATA8(0x1A);
	LCD_WR_REG(0x36); //MX, MY, RGB mode
	LCD_WR_DATA8(0xC0);

//    LCD_WR_REG(0x36); //MX, MY, RGB mode
//    LCD_WR_DATA8(0xA0);

//    LCD_WR_REG(0x36); //MX, MY, RGB mode
//    LCD_WR_DATA8(0x00);
//
//    LCD_WR_REG(0x36); //MX, MY, RGB mode
//    LCD_WR_DATA8(0x60);
	//------------------------------------ST7735S Gamma Sequence-----------------------------------------//
	LCD_WR_REG(0xE0);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x22);
	LCD_WR_DATA8(0x07);
	LCD_WR_DATA8(0x0A);
	LCD_WR_DATA8(0x2E);
	LCD_WR_DATA8(0x30);
	LCD_WR_DATA8(0x25);
	LCD_WR_DATA8(0x2A);
	LCD_WR_DATA8(0x28);
	LCD_WR_DATA8(0x26);
	LCD_WR_DATA8(0x2E);
	LCD_WR_DATA8(0x3A);
	LCD_WR_DATA8(0x00);
	LCD_WR_DATA8(0x01);
	LCD_WR_DATA8(0x03);
	LCD_WR_DATA8(0x13);
	LCD_WR_REG(0xE1);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x16);
	LCD_WR_DATA8(0x06);
	LCD_WR_DATA8(0x0D);
	LCD_WR_DATA8(0x2D);
	LCD_WR_DATA8(0x26);
	LCD_WR_DATA8(0x23);
	LCD_WR_DATA8(0x27);
	LCD_WR_DATA8(0x27);
	LCD_WR_DATA8(0x25);
	LCD_WR_DATA8(0x2D);
	LCD_WR_DATA8(0x3B);
	LCD_WR_DATA8(0x00);
	LCD_WR_DATA8(0x01);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x13);
	//------------------------------------End ST7735S Gamma Sequence-----------------------------------------//
	LCD_WR_REG(0x3A); //65k mode
	LCD_WR_DATA8(0x05);
	LCD_WR_REG(0x29); //Display on

	LCD_Clear(WHITE);
}  

void LCD_Clear(uint16_t color)
{
	uint16_t index=0;      
	uint16_t totalpoint=lcddev.width;
	totalpoint*=lcddev.height; 	//�õ��ܵ���
	LCD_SetCursor(0x00,0x0000);	//���ù��λ�� 
	LCD_WriteRAM_Prepare();     //��ʼд��GRAM	 	  
	for(index=0;index<totalpoint;index++)
	{
		LCD_WR_DATA(color);
	}
}  

void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color)
{
	uint16_t i,j;
	uint16_t xlen=0;
	xlen=ex-sx+1;
	for(i=sy;i<=ey;i++)
	{
	 	LCD_SetCursor(sx,i);      				//���ù��λ��
		LCD_WriteRAM_Prepare();     			//��ʼд��GRAM
		for(j=0;j<xlen;j++)LCD_WR_DATA(color);	//���ù��λ��
	}
}

void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
	uint16_t t;
	int xerr=0,yerr=0,delta_x,delta_y,distance;
	int incx,incy,uRow,uCol;
	delta_x=x2-x1;
	delta_y=y2-y1;
	uRow=x1;
	uCol=y1;
	if(delta_x>0)incx=1;
	else if(delta_x==0)incx=0;
	else {incx=-1;delta_x=-delta_x;}
	if(delta_y>0)incy=1;
	else if(delta_y==0)incy=0;
	else{incy=-1;delta_y=-delta_y;}
	if( delta_x>delta_y)distance=delta_x;
	else distance=delta_y;
	for(t=0;t<=distance+1;t++)
	{
		LCD_DrawPoint(uRow, uCol, color);
		xerr+=delta_x ;
		yerr+=delta_y ;
		if(xerr>distance)
		{
			xerr-=distance;
			uRow+=incx;
		}
		if(yerr>distance)
		{
			yerr-=distance;
			uCol+=incy;
		}
	}
}
